﻿using UnityEditor;
using UnityEngine;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using LuaFramework;

public class Packager {
    public static string platform = string.Empty;
    static List<string> paths = new List<string>();
    static List<string> files = new List<string>();
    static List<AssetBundleBuild> maps = new List<AssetBundleBuild>();

    ///-----------------------------------------------------------
    static string[] exts = { ".txt", ".xml", ".lua", ".assetbundle", ".json" };
    static bool CanCopy(string ext) {   //能不能复制
        foreach (string e in exts) {
            if (ext.Equals(e)) return true;
        }
        return false;
    }

    /// <summary>
    /// 载入素材
    /// </summary>
    static UnityEngine.Object LoadAsset(string file) {
        if (file.EndsWith(".lua")) file += ".txt";
        return AssetDatabase.LoadMainAssetAtPath("Assets/LuaFramework/Examples/Builds/" + file);
    }

    [MenuItem("LuaFramework/Build All Resource", false, 100)]
    static void BuildAllResources(){
        BuildLuaResources();
		BuildAssetResource();
        BuildFileIndex();
    }


    [MenuItem("LuaFramework/Build Lua", false, 101)]
    static void BuildLuaResources(){
        string streamPath = Application.streamingAssetsPath+"/lua";
        if (Directory.Exists(streamPath)) {
            Directory.Delete(streamPath, true);
        }
        Directory.CreateDirectory(streamPath);
        AssetDatabase.Refresh();

        maps.Clear();
//        if (AppConst.LuaBundleMode)
//        {
            HandleLuaBundle();

            string resPath = "Assets/StreamingAssets";
            BuildPipeline.BuildAssetBundles(resPath, maps.ToArray(), BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget);
    
            string tempDir = Application.dataPath + "/_lua";
            if (Directory.Exists(tempDir))
                Directory.Delete(tempDir, true);
			tempDir = Application.dataPath + "/" + AppConst.LuaTempDir;
			if (Directory.Exists(tempDir))
				Directory.Delete(tempDir, true);
		
            AssetDatabase.Refresh();
//        }
//        else
//        {
//            HandleLuaFile();
//        }


        //复制当前项目的脚本到Export目录中
        string destFolder = Application.dataPath.Substring(0,Application.dataPath.Length-7)+"/Exports/"+GetFolderByBuildTarget(EditorUserBuildSettings.activeBuildTarget)+"/lua";
        if (Directory.Exists(destFolder))
            Directory.Delete(destFolder,true);
        Directory.CreateDirectory(destFolder);

        string[] files = Directory.GetFiles(streamPath);
        for (int i = 0; i < files.Length; ++i)
        {
            if (files[i].IndexOf("lua_" + EditorSettings.projectGenerationRootNamespace.ToLower()) > 0)
            {
                File.Copy(files[i], destFolder + "/"+Path.GetFileName(files[i]),true);
            }
        }
    }

	[MenuItem("LuaFramework/Build Asset Resource", false, 102)]
    /// <summary>
    /// 生成绑定素材
    /// </summary>
    static void BuildAssetResource() {
		string streamPath = Application.streamingAssetsPath+"/"+EditorSettings.projectGenerationRootNamespace.ToLower();
        if (Directory.Exists(streamPath)) {
            Directory.Delete(streamPath, true);
        }
        Directory.CreateDirectory(streamPath);
        AssetDatabase.Refresh();

		BuildPipeline.BuildAssetBundles(streamPath,BuildAssetBundleOptions.None, EditorUserBuildSettings.activeBuildTarget);
       
        AssetDatabase.Refresh();

        //复制一份到项目外面
        string dest = Application.dataPath.Substring(0,Application.dataPath.Length-7)+"/Exports/"+GetFolderByBuildTarget(EditorUserBuildSettings.activeBuildTarget)+"/"+EditorSettings.projectGenerationRootNamespace.ToLower();
        if (Directory.Exists(dest))
            Directory.Delete(dest, true);
        
        CopyDirectory(streamPath,dest,true);
        if (Directory.Exists(streamPath + "raw"))
        {
            dest = dest + "raw";
            if (Directory.Exists(dest))
                Directory.Delete(dest, true);
            CopyDirectory(streamPath + "raw",dest,true);
        }
    }

    static string GetFolderByBuildTarget(BuildTarget tar){
        if (tar == BuildTarget.Android)
            return "Android";
        if (tar == BuildTarget.iOS)
            return "iOS";
        return "PC";
    }

    static void CopyDirectory(string sourceDirName, string destDirName, bool copySubDirs)
    {
        // Get the subdirectories for the specified directory.
        DirectoryInfo dir = new DirectoryInfo(sourceDirName);

        if (!dir.Exists)
        {
            return;
        }

        DirectoryInfo[] dirs = dir.GetDirectories();
        // If the destination directory doesn't exist, create it.
        if (!Directory.Exists(destDirName))
        {
            Directory.CreateDirectory(destDirName);
        }

        // Get the files in the directory and copy them to the new location.
        FileInfo[] files = dir.GetFiles();
        foreach (FileInfo file in files)
        {
            string temppath = Path.Combine(destDirName, file.Name);
            file.CopyTo(temppath, true);
        }

        // If copying subdirectories, copy them and their contents to new location.
        if (copySubDirs)
        {
            foreach (DirectoryInfo subdir in dirs)
            {
                string temppath = Path.Combine(destDirName, subdir.Name);
                CopyDirectory(subdir.FullName, temppath, copySubDirs);
            }
        }
    }

    static void AddBuildMap(string bundleName, string pattern, string path) {
        string[] files = Directory.GetFiles(path, pattern);
        if (files.Length == 0) return;

        for (int i = 0; i < files.Length; i++) {
            files[i] = files[i].Replace('\\', '/');
        }
        AssetBundleBuild build = new AssetBundleBuild();
        build.assetBundleName = bundleName;
        build.assetNames = files;
        maps.Add(build);
    }

   
    /// <summary>
    /// 处理Lua代码包
    /// </summary>
    static void HandleLuaBundle() {
        string streamDir = Application.dataPath + "/" + AppConst.LuaTempDir;
        if (!Directory.Exists(streamDir)) Directory.CreateDirectory(streamDir);

        string[] srcDirs = { Application.dataPath+"/Lua", Application.dataPath + "/LuaFramework/ToLua/Lua" };
        for (int i = 0; i < srcDirs.Length; i++) {
            if (AppConst.LuaByteMode) {
                string sourceDir = srcDirs[i];
                string[] files = Directory.GetFiles(sourceDir, "*.lua", SearchOption.AllDirectories);
                int len = sourceDir.Length;

                if (sourceDir[len - 1] == '/' || sourceDir[len - 1] == '\\') {
                    --len;
                }
                for (int j = 0; j < files.Length; j++) {
                    string str = files[j].Remove(0, len);
                    string dest = streamDir + str + ".bytes";
                    string dir = Path.GetDirectoryName(dest);
                    Directory.CreateDirectory(dir);
                    EncodeLuaFile(files[j], dest);
                }    
            } else {
                ToLuaMenu.CopyLuaBytesFiles(srcDirs[i], streamDir);
            }
        }
        string[] dirs = Directory.GetDirectories(streamDir, "*", SearchOption.AllDirectories);
        for (int i = 0; i < dirs.Length; i++) {
            string name = dirs[i].Replace(streamDir, string.Empty);
            name = name.Replace('\\', '_').Replace('/', '_');
            name = "lua/lua" + name.ToLower() + AppConst.ExtName;

            string path = "Assets" + dirs[i].Replace(Application.dataPath, "");
            AddBuildMap(name, "*.bytes", path);
        }
        AddBuildMap("lua/lua" + AppConst.ExtName, "*.bytes", "Assets/" + AppConst.LuaTempDir);

        //-------------------------------处理非Lua文件----------------------------------
//        string luaPath = AppDataPath + "/StreamingAssets/lua/";
//        for (int i = 0; i < srcDirs.Length; i++) {
//            paths.Clear(); files.Clear();
//            string luaDataPath = srcDirs[i].ToLower();
//            Recursive(luaDataPath);
//            foreach (string f in files) {
//                if (f.EndsWith(".meta") || f.EndsWith(".lua")) continue;
//                string newfile = f.Replace(luaDataPath, "");
//                string path = Path.GetDirectoryName(luaPath + newfile);
//                if (!Directory.Exists(path)) Directory.CreateDirectory(path);
//
//                string destfile = path + "/" + Path.GetFileName(f);
//                File.Copy(f, destfile, true);
//            }
//        }
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 处理Lua文件
    /// </summary>
    static void HandleLuaFile() {
        string resPath = AppDataPath + "/StreamingAssets/";
        string luaPath = resPath + "/lua/";

        //----------复制Lua文件----------------
        if (!Directory.Exists(luaPath)) {
            Directory.CreateDirectory(luaPath); 
        }
        string[] luaPaths = { AppDataPath + "/lua/", 
                              AppDataPath + "/LuaFramework/Tolua/Lua/" };

        for (int i = 0; i < luaPaths.Length; i++) {
            paths.Clear(); files.Clear();
            string luaDataPath = luaPaths[i].ToLower();
            Recursive(luaDataPath);
            int n = 0;
            foreach (string f in files) {
                if (f.EndsWith(".meta")) continue;
                string newfile = f.Replace(luaDataPath, "");
                string newpath = luaPath + newfile;
                string path = Path.GetDirectoryName(newpath);
                if (!Directory.Exists(path)) Directory.CreateDirectory(path);

                if (File.Exists(newpath)) {
                    File.Delete(newpath);
                }
                if (AppConst.LuaByteMode) {
                    EncodeLuaFile(f, newpath);
                } else {
                    File.Copy(f, newpath, true);
                }
                UpdateProgress(n++, files.Count, newpath);
            } 
        }
        EditorUtility.ClearProgressBar();
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// md5 streamingAssets下面所有文件
    /// </summary>
    [MenuItem("LuaFramework/Md5 Files", false, 200)]
    static void BuildFileIndex() {
        string resPath = AppDataPath + "/StreamingAssets/";

		///-------------------删除一些多余的文件------------------
		if(File.Exists(resPath+"StreamingAssets")){
			File.Delete(resPath+"StreamingAssets");
		}
		if(File.Exists(resPath+"StreamingAssets.manifest")){
			File.Delete(resPath+"StreamingAssets.manifest");
		}
		if(File.Exists(resPath+"StreamingAssets.meta")){
			File.Delete(resPath+"StreamingAssets.meta");
		}
		if(File.Exists(resPath+"StreamingAssets.manifest.meta")){
			File.Delete(resPath+"StreamingAssets.manifest.meta");
		}
		string[] dirs = Directory.GetDirectories(resPath);
		for(int i = 0 ;i<dirs.Length ;++i){
			string dir = dirs[i];
			if(dir.IndexOf("StreamingAssets/lua")>0 || dir.IndexOf("StreamingAssets/mainapp")>0){
				continue;
			}
			if(File.Exists(dir + "/comm.unity3d")){
				File.Delete(dir + "/comm.unity3d");
			}
			if(File.Exists(dir + "/comm.unity3d.meta")){
				File.Delete(dir + "/comm.unity3d.meta");
			}
			if(File.Exists(dir + "/comm.unity3d.manifest")){
				File.Delete(dir + "/comm.unity3d.manifest");
			}
			if(File.Exists(dir + "/comm.unity3d.manifest.meta")){
				File.Delete(dir + "/comm.unity3d.manifest.meta");
			}
		}

        string rootNS = EditorSettings.projectGenerationRootNamespace.ToLower();
        bool isMainApp = rootNS.Equals("mainapp");
        ///----------------------创建文件列表-----------------------
        string newFilePath = resPath + "/"+rootNS+".txt";
        if (File.Exists(newFilePath)) File.Delete(newFilePath);

        paths.Clear(); files.Clear();
        Recursive(resPath);

        FileStream fs = new FileStream(newFilePath, FileMode.CreateNew);
        StreamWriter sw = new StreamWriter(fs);
        for (int i = 0; i < files.Count; i++) {
            string file = files[i];
            string ext = Path.GetExtension(file);
            if (file.EndsWith(".meta") || file.Contains(".DS_Store")) continue;

            string md5 = Util.md5file(file);
            string value = file.Replace(resPath, string.Empty);

            if (value.IndexOf("/") > 0) //只md5 文件夹下面的，不处理StreamingAssets目录下面的文件
            {
                if (value.StartsWith("lua/lua_") && (value.IndexOf("lua/lua_"+rootNS) == -1||value.StartsWith("lua/lua.unity")) )
                {
                    continue;
                }
                sw.WriteLine(value + "|" + md5);
            }
        }
        sw.Close(); fs.Close();
        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 数据目录
    /// </summary>
    static string AppDataPath {
        get { return Application.dataPath.ToLower(); }
    }

    /// <summary>
    /// 遍历目录及其子目录
    /// </summary>
    static void Recursive(string path) {
        string[] names = Directory.GetFiles(path);
        string[] dirs = Directory.GetDirectories(path);
        foreach (string filename in names) {
            string ext = Path.GetExtension(filename);
            if (ext.Equals(".meta")) continue;
            files.Add(filename.Replace('\\', '/'));
        }
        foreach (string dir in dirs) {
            paths.Add(dir.Replace('\\', '/'));
            Recursive(dir);
        }
    }

    static void UpdateProgress(int progress, int progressMax, string desc) {
        string title = "Processing...[" + progress + " - " + progressMax + "]";
        float value = (float)progress / (float)progressMax;
        EditorUtility.DisplayProgressBar(title, desc, value);
    }

    public static void EncodeLuaFile(string srcFile, string outFile) {
        if (!srcFile.ToLower().EndsWith(".lua")) {
            File.Copy(srcFile, outFile, true);
            return;
        }
        bool isWin = true; 
        string luaexe = string.Empty;
        string args = string.Empty;
        string exedir = string.Empty;
        string currDir = Directory.GetCurrentDirectory();
        if (Application.platform == RuntimePlatform.WindowsEditor) {
            isWin = true;
            luaexe = "luajit.exe";
            args = "-b " + srcFile + " " + outFile;
            exedir = AppDataPath.Replace("assets", "") + "LuaEncoder/luajit/";
        } else if (Application.platform == RuntimePlatform.OSXEditor) {
            isWin = false;
            luaexe = "./luajit";
            args = "-b " + srcFile + " " + outFile;
            exedir = AppDataPath.Replace("assets", "") + "LuaEncoder/luajit_mac/";
        }
        Directory.SetCurrentDirectory(exedir);
        ProcessStartInfo info = new ProcessStartInfo();
        info.FileName = luaexe;
        info.Arguments = args;
        info.WindowStyle = ProcessWindowStyle.Hidden;
        info.UseShellExecute = isWin;
        info.ErrorDialog = true;
        Util.Log(info.FileName + " " + info.Arguments);

        Process pro = Process.Start(info);
        pro.WaitForExit();
        Directory.SetCurrentDirectory(currDir);
    }

}